package com.liming.common.util;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.collect.Lists;
import com.liming.common.exception.BusinessException;
import com.liming.common.pojo.dto.PageDTO;
import com.liming.common.pojo.vo.PageVO;

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * @author liming
 * @date 2025/2/12
 */
public class PageUtils {

    /**
     * 设计该函数只是为了在OpenFeign调用时，返回的JSON对象 （经过自定义序列化器） （避免重复两次）。
     * 分页类型转换
     *
     * @param feignResult      openFeign 返回的分页对象
     * @param result           返回给前端的分页对象
     * @param resultFieldClazz result 的泛型类
     * @param <T>              openFeign 返回的分页对象泛型类
     * @param <R>              result 泛型类
     */
    public static <T, R> void copyProperties(PageVO<T> feignResult, PageVO<R> result, Class<R> resultFieldClazz) {
        // 拷贝除records外的属性 拷贝了的话 里面的records的属性为 FeignCouponVO （浅拷贝问题）
        BeanUtils.copyProperties(feignResult, result, "records");
        result.setRecords(feignResult.getRecords().stream().map(feign -> {
            try {
                R resultField = resultFieldClazz.getDeclaredConstructor().newInstance();
                BeanUtils.copyProperties(feign, resultField);
                return resultField;
            } catch (Exception e) {
                throw new BusinessException("分页类型转换失败");
            }
        }).toList());
    }

    /**
     * 设计该函数只是为了在OpenFeign调用时，返回的JSON对象 （经过自定义序列化器） （避免重复两次）。
     * 分页类型转换
     *
     * @param feignResult             openFeign 返回的分页对象
     * @param result                  返回给前端的分页对象
     * @param resultFieldClazz        result 的泛型类
     * @param fieldInResultFieldName  result 中需要转换的字段中的字段名
     * @param fieldInResultFieldClazz result 中需要转换的字段中的字段类型
     * @param <T>                     openFeign 返回的分页对象泛型类
     * @param <R>                     result 泛型类
     */
    public static <T, R, F> void copyPropertiesAndField(PageVO<T> feignResult, PageVO<R> result, Class<R> resultFieldClazz, String fieldInResultFieldName, Class<F> fieldInResultFieldClazz) {
        // 拷贝除records外的属性 拷贝了的话 里面的records的属性为 FeignCouponVO （浅拷贝问题）
        BeanUtils.copyProperties(feignResult, result, "records");
        result.setRecords(feignResult.getRecords().stream().map(feign -> {
            try {
                R resultField = resultFieldClazz.getDeclaredConstructor().newInstance();
                BeanUtils.copyProperties(feign, resultField);
                setFieldInResultField(fieldInResultFieldName, fieldInResultFieldClazz, feign, resultField);
                return resultField;
            } catch (Exception e) {
                throw new BusinessException("分页类型转换失败");
            }
        }).toList());
    }

    private static <T, R, F> void setFieldInResultField(String fieldName, Class<F> voFieldClazz, T feign, R resultField) throws NoSuchFieldException, IllegalAccessException {
        // 取出 Feign中的字段
        Field feignField = feign.getClass().getDeclaredField(fieldName);
        feignField.setAccessible(true);
        Object objectFeignList = feignField.get(feign);
        if (objectFeignList instanceof List feignList) {
            List voList = feignList.stream().map(twoFeign -> BeanUtils.toBean(twoFeign, voFieldClazz)).toList();
            Field voField = resultField.getClass().getDeclaredField(fieldName);
            voField.setAccessible(true);
            voField.set(resultField, voList);
        }
    }

    /**
     * 将MP中的IPage对象 转换为PageVO对象 （适应我的OpenFeign解码器）
     *
     * @param page     MP - IPage对象
     * @param function 转换函数
     * @param <T>      page - records的类型
     * @param <R>      pageVo - records的类型
     * @return PageVO对象
     */
    public static <T, R> PageVO<R> convert(IPage<T> page, Function<T, R> function) {
        PageVO<R> result = new PageVO<>();
        // 拷贝除records外的属性 拷贝了的话 里面的records的属性为 FeignCouponVO （浅拷贝问题）
        BeanUtils.copyProperties(page, result, "records");
        result.setRecords(page.getRecords().stream().map(function).toList());
        return result;
    }

    /**
     * 将MP中的IPage对象 转换为PageVO对象 （适应我的OpenFeign解码器）
     *
     * @param page      MP - IPage对象
     * @param function  转换函数
     * @param predicate 过滤条件
     * @param <T>       page - records的类型
     * @param <R>       pageVo - records的类型
     * @return PageVO对象
     */
    public static <T, R> PageVO<R> convert(IPage<T> page, Function<T, R> function, Predicate<R> predicate) {
        PageVO<R> result = new PageVO<>();
        // 拷贝除records外的属性 拷贝了的话 里面的records的属性为 FeignCouponVO （浅拷贝问题）
        BeanUtils.copyProperties(page, result, "records");
        result.setRecords(page.getRecords().stream().map(function).filter(predicate).toList());
        return result;
    }

    /**
     * 分页数据
     *
     * @param list 所有数据
     * @param page 当前页
     * @param size 每页数量
     * @return 分页数据
     */
    public static List<?> pageByAllData(List<?> list, int page, int size) {
        return Lists.partition(list, size).get(page - 1);
    }

    public static <R> PageVO<R> emptyPage() {
        PageVO<R> vo = new PageVO<>();
        vo.setCurrent(1);
        vo.setPages(1);
        vo.setTotal(0);
        vo.setSize(10);
        vo.setRecords(Collections.emptyList());
        return vo;
    }

    public static <R> PageVO<R> emptyPage(PageDTO page) {
        PageVO<R> vo = new PageVO<>();
        vo.setCurrent(page.getCurrent());
        vo.setPages(1);
        vo.setTotal(0);
        vo.setSize(page.getSize());
        vo.setRecords(Collections.emptyList());
        return vo;
    }
}
